<template>
  <!-- 默认插槽用于包裹可能出错的子组件 -->
  <slot v-if="!hasError" />
  
  <!-- 错误降级UI -->
  <div v-else class="error-boundary">
    <el-result
      icon="error"
      title="组件渲染异常"
      :sub-title="errorMessage"
    >
      <template #extra>
        <el-button 
          type="primary" 
          @click="handleReset"
          :loading="resetting"
        >
          {{ resetButtonText }}
        </el-button>
      </template>
    </el-result>
  </div>
</template>

<script lang="ts" setup>
import { ref, onErrorCaptured } from 'vue'
import { ElResult, ElButton } from 'element-plus'

const props = withDefaults(defineProps<{
  // 自定义错误提示
  fallbackText?: string
  // 重置按钮文字
  resetButtonText?: string
  // 是否自动重置错误状态
  autoReset?: boolean
}>(), {
  fallbackText: '组件渲染过程中发生错误',
  resetButtonText: '重新加载',
  autoReset: false
})

const hasError = ref(false)
const resetting = ref(false)
const errorMessage = ref('')
const errorInfo = ref<Error | null>(null)

// 错误处理函数
const handleError = (err: Error) => {
  hasError.value = true
  errorMessage.value = props.fallbackText
  errorInfo.value = err
  
  // 自动重置逻辑
  if (props.autoReset) {
    setTimeout(handleReset, 3000)
  }
  
  // 可以在这里添加错误上报逻辑
  console.error('ErrorBoundary 捕获到错误:', err)
}

// 重置组件状态
const handleReset = () => {
  resetting.value = true
  setTimeout(() => {
    hasError.value = false
    errorInfo.value = null
    resetting.value = false
  }, 500)
}

// 捕获组件错误
onErrorCaptured((err: Error) => {
  handleError(err)
  return false // 阻止错误继续向上传播
})

// 暴露方法供父组件调用
defineExpose({
  /**
   * 手动触发错误处理
   * @param error 错误对象
   */
  triggerError: handleError,
  /**
   * 手动重置错误状态
   */
  reset: handleReset
})
</script>

<style lang="scss" scoped>
.error-boundary {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f5f7fa;
  padding: 20px;
  
  :deep(.el-result) {
    padding: 20px;
    background-color: white;
    border-radius: 4px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  }
}
</style>